#define _POSIX_C_SOURCE 200809L

#include <stdlib.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/interfaces/wlr_touch.h>
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/util/log.h>
#include "backend/sylixosinput.h"
#include "util/signal.h"

void destroy_sylixosinput_input_device(struct wlr_sylixosinput_input_device *dev) {
    if (dev->keyboard.impl) {
        wlr_keyboard_finish(&dev->keyboard);
    }
	if (dev->pointer.impl) {
		wlr_pointer_finish(&dev->pointer);
	}

	wl_list_remove(&dev->link);
	free(dev);
}

bool wlr_input_device_is_sylixosinput(struct wlr_input_device *wlr_dev) {
	switch (wlr_dev->type) {
    case WLR_INPUT_DEVICE_KEYBOARD:
        return wlr_keyboard_from_input_device(wlr_dev)->impl ==
            &sylixosinput_keyboard_impl;
	case WLR_INPUT_DEVICE_POINTER:
		return wlr_pointer_from_input_device(wlr_dev)->impl ==
			&sylixosinput_pointer_impl;
	default:
		return false;
	}
}

void handle_device_added(struct wlr_sylixosinput_backend *backend) {
	struct wlr_sylixosinput_input_device *dev =
		calloc(1, sizeof(struct wlr_sylixosinput_input_device));
	if (dev == NULL) {
		wlr_log_errno(WLR_ERROR, "failed to allocate wlr_sylixosinput_input_device");
		return;
	}

	wl_list_insert(&backend->devices, &dev->link);
	backend->device = dev;

    init_device_keyboard(dev);
    wlr_signal_emit_safe(&backend->backend.events.new_input, &dev->keyboard.base);

    init_device_pointer(dev);
    wlr_signal_emit_safe(&backend->backend.events.new_input, &dev->pointer.base);
}

void handle_xmse_event(struct wlr_sylixosinput_backend *state, int fd)
{
    struct wlr_sylixosinput_input_device *dev = state->device;
    mouse_event_notify mse_event;
    static int button_state = 0;

    read(fd, (void *)&mse_event, sizeof(mouse_event_notify));

    if (mse_event.ctype == MOUSE_CTYPE_REL) {
        if (mse_event.xmovement || mse_event.ymovement)
            handle_pointer_motion(&mse_event, &dev->pointer);

        if (mse_event.kstat != button_state) {
            button_state = mse_event.kstat;
            handle_pointer_button(&mse_event, &dev->pointer);
        }

        if (mse_event.wscroll[0]) {
            handle_pointer_axis(&mse_event, &dev->pointer);
        }
    } else {
        // TODO: handle touch events
    }
}

void handle_xkbd_event(struct wlr_sylixosinput_backend *state, int fd)
{
    struct wlr_sylixosinput_input_device *dev = state->device;
    keyboard_event_notify kbd_event;

    read(fd, (void *)&kbd_event, sizeof(keyboard_event_notify));

    handle_keyboard_key(&kbd_event, &dev->keyboard);
}
